package persistencia.carreras.pruebas;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.File;

import java.util.HashMap;
import java.util.Map;

import modelo.geometria.Vector;
import modelo.seniales.ColorSemaforo;
import modelo.seniales.EsquinaSemaforo;
import modelo.seniales.ISenial;
import modelo.seniales.Semaforo;
import modelo.seniales.carteles.CirculacionExclusiva;
import modelo.seniales.carteles.LimiteVelocidad;
import modelo.vehiculos.Automovil;
import modelo.vehiculos.SentidoVehiculo;
import modelo.vehiculos.Vehiculo;
import modelo.controles.Policia;
import modelo.controles.Camara;
import persistencia.IAlmacen;
import persistencia.IEnsamblador;
import persistencia.IGondola;
import persistencia.carreras.ClaveValor;
import persistencia.carreras.EnsambladorClaveValor;
import persistencia.carreras.ensambladores.general.EnsambladorCamara;
import persistencia.carreras.ensambladores.general.EnsambladorCirculacionExclusiva;
import persistencia.carreras.ensambladores.general.EnsambladorLimiteVelocidad;
import persistencia.carreras.ensambladores.general.EnsambladorPolicia;
import persistencia.carreras.ensambladores.general.EnsambladorSemaforo;
import persistencia.compartido.Tipo;
import persistencia.csv.AlmacenCSV;
import persistencia.excepciones.StringDeConexionIncompatible;

import compartido.IEntidad;

public class TestEnsambladores {

	IAlmacen almacen = null;
	Map<Tipo<IEntidad>, IEnsamblador> configuracion;
	
	@Before
	public void setUp() throws Exception {
		almacen = new AlmacenCSV();
		
		configuracion = new HashMap<Tipo<IEntidad>, IEnsamblador>();
		
		configuracion.put(new Tipo<IEntidad>(Semaforo.class),new EnsambladorSemaforo());
		configuracion.put(new Tipo<IEntidad>(LimiteVelocidad.class),new EnsambladorLimiteVelocidad());
		configuracion.put(new Tipo<IEntidad>(CirculacionExclusiva.class), new EnsambladorCirculacionExclusiva());
		configuracion.put(new Tipo<IEntidad>(ClaveValor.class), new EnsambladorClaveValor());
		configuracion.put(new Tipo<IEntidad>(Policia.class), new EnsambladorPolicia());
		configuracion.put(new Tipo<IEntidad>(Camara.class), new EnsambladorCamara());
		
		for (Tipo<IEntidad> tipo : configuracion.keySet()) {
			almacen.registrarEnsamblador(tipo, configuracion.get(tipo));
		
			File f = new File(tipo.getNombre()+".csv");
			if (f.exists())
				f.delete();
		}
	}

	@After
	public void tearDown() throws Exception {
	}

	protected void abrirAlmacen() {
		try {
			almacen.abrir("csv:.");
		} catch (StringDeConexionIncompatible e) {
			fail ("No detecta correctamente el string de conexión.");
		}	
	}
	
	protected void prepararGondola(IEntidad elemento) {
		IGondola gondola = almacen.crearGondola(new Tipo<IEntidad>(elemento.getClass()));

		gondola.agregar(elemento);
		gondola.guardar();		
	}
	
	protected IEntidad obtenerCopiaDe(IEntidad original) {
		abrirAlmacen();
		prepararGondola(original);
		
		almacen.cerrar();
		System.gc();
		
		abrirAlmacen();
		Tipo<IEntidad> tipo = new Tipo<IEntidad>(original.getClass());
		IGondola gondola = almacen.crearGondola(tipo);
		IEntidad entidad = gondola.obtener(original.getIdentificador());
		if (entidad == null)
			fail ("No se obtiene una instancia correcta como copia.");
		
		almacen.cerrar();
		return entidad;
	}
	
	@Test
	public void testSemaforo() {	
		long identificador = 5;
		
		Semaforo original = new Semaforo(identificador, new Vector(5,5), 1, EsquinaSemaforo.INICIO, ColorSemaforo.ROJO, 10);
		
		Semaforo copia = (Semaforo) obtenerCopiaDe(original);
		
		assertEquals(0, original.getIdentificador().compareTo(copia.getIdentificador()));
		assertEquals(0, original.getPosicion().compareTo(copia.getPosicion()));
	}
	
	@Test
	public void testLimiteVelocidad() {
		long identificador = 60;
		LimiteVelocidad original = new LimiteVelocidad(identificador, new Vector(3,3), 60, true);
		
		LimiteVelocidad copia = (LimiteVelocidad) obtenerCopiaDe(original);
				
		assertEquals(0,original.getIdentificador().compareTo(copia.getIdentificador()));
		assertEquals(0.0, original.getPosicion().getDistancia(copia.getPosicion()), 0.0);
		assertEquals(original.getVelocidad(),copia.getVelocidad(),0.0);
		assertEquals(original.esLimiteDeVelocidadMaxima(),copia.esLimiteDeVelocidadMaxima());
	}
	
	@Test 
	public void testCirculacionExclusiva() {
		long identificador = 60;

		
		
		Vector posicionInicial = new Vector(0,0);
		Vector posicionFinal = new Vector(0,10);
		SentidoVehiculo sentidoVehiculo = SentidoVehiculo.NORTE;
		double largo = 3;
		double ancho = 1;
		double velocidadActual = 30;
		double velocidadMaxima = 100;
		double aceleracionMaxima = 5;
		double frenadoMaximo = 50;
		
		Vehiculo v = new Automovil(null, posicionInicial, posicionFinal, sentidoVehiculo, largo, ancho, velocidadActual, velocidadMaxima, aceleracionMaxima, frenadoMaximo);
		
		CirculacionExclusiva original = new CirculacionExclusiva(identificador, new Vector(2,2), v);
		
		CirculacionExclusiva copia = (CirculacionExclusiva) obtenerCopiaDe(original);
		
		assertEquals( 0, original.getIdentificador().compareTo(copia.getIdentificador()) );
		//assertEquals( original.getVehiculoPermitido() , copia.getVehiculoPermitido() );
	}

	@Test
	public void testClaveValor() {
		ClaveValor original = new ClaveValor("VARIABLE", "VALOR");
		
		ClaveValor copia = (ClaveValor) obtenerCopiaDe(original);
		
		assertEquals(0, copia.compareTo(original));
	}
	
	@Test
	public void testPolicia() {
		LimiteVelocidad cartel = new LimiteVelocidad(1, new Vector(1,0), 60, true);
		
		abrirAlmacen();
		prepararGondola(cartel);
		almacen.cerrar();
		
		Policia original = new Policia(1, new Vector(0,0), 1, 10, cartel);
		
		Policia copia = (Policia) obtenerCopiaDe(original);
		
		assertEquals(0, original.getIdentificador().compareTo(copia.getIdentificador()) );
		ISenial senial = copia.getSenial();
		assertNotNull(senial);
		assertTrue(senial instanceof LimiteVelocidad);
		LimiteVelocidad copia_senial = (LimiteVelocidad)copia.getSenial();
		assertEquals(0, cartel.getIdentificador().compareTo(copia_senial.getIdentificador()) );
	}
	
	@Test
	public void testCamara() {
		LimiteVelocidad cartel = new LimiteVelocidad(1, new Vector(1,0), 60, true);

		abrirAlmacen();
		prepararGondola(cartel);
		almacen.cerrar();
		
		Camara original = new Camara(1, new Vector(0,0), 1, 10, cartel);
		
		Camara copia = (Camara) obtenerCopiaDe(original);
		
		assertEquals(0, (original.getIdentificador().compareTo(copia.getIdentificador())) );
		//assertEquals(original.getSenial(), copia.getSenial());
	}
}